package work.month07.day01;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

public class FileCopyHelper {

	/**
	 * 使用 传统IO 实现文件复制
	 * @param src 被复制文件
	 * @param dst 复制后的文件
	 * @throws IllegalAccessException 
	 */
	public static void copy(File src, File dst) throws IllegalAccessException {
		final long begin = System.nanoTime(); // 返回毫微秒 (不是从历元开始计时)
		// 1. 判断参数是否异常
		if (src == null || dst == null || !src.isFile() || !dst.isFile())
			throw new IllegalAccessException("非法参数异常");

		// 2. 创建相关变量
		FileInputStream in = null;
		FileOutputStream out = null;
		byte[] b = new byte[1001024]; // 存储读取到的数据
		int len = 0; // 代表每次读取到的字节数

		try {
		// 3. 将数据从 in 中读取，然后写入到 out 所代表的文件中
			in = new FileInputStream(src);
			out = new FileOutputStream(dst);
			while ((len = in.read(b)) != -1) {
				out.write(b, 0, len);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
		// 4. 关闭资源
			if (in != null)
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			if (out != null)
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		
		final long end = System.nanoTime();
		System.out.println("使用 InputStream 和 OutputStream 复制文件用时: " + (end - begin) + "ns.");
	}

	/**
	 * 使用 Channel 和 Buffer 完成文件复制
	 * @param src 被复制的文件路径
	 * @param dst 复制后的文件存放路径
	 * @throws IllegalAccessException 
	 */
	public static void copy(Path src, Path dst) throws IllegalAccessException {
		final long begin = System.nanoTime(); // 返回毫微秒 (不是从历元开始计时)
		// 1. 检查参数
		if (src == null || dst == null || !Files.exists(src) || !Files.exists(dst))
			throw new IllegalAccessException("非法参数异常");
		// 2. 创建相关变量
		FileChannel readChannel = null;  // 读通道
		FileChannel writeChannel = null; // 写通道
		ByteBuffer buffer = null;        // 进行读和写
		int len = 0;                     // 每次读取的长度
		
		// 3. 为相关变量赋值，通过 readChannel 将数据读取的到 buffer 中，然后将 buffer 中的数据写入到 writeChannel 中
		try {
			readChannel = FileChannel.open(src, StandardOpenOption.READ);
			writeChannel = FileChannel.open(dst, StandardOpenOption.WRITE);
			buffer = ByteBuffer.allocate(1001024);
			while ( (len = readChannel.read(buffer)) != -1 ) {
				buffer.flip();   // 固定读取区间
				writeChannel.write(buffer);  // 写入数据
				buffer.clear();  // 重置缓冲区
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 4. 关闭资源
			if (readChannel != null)
				try {
					readChannel.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			if (writeChannel != null)
				try {
					writeChannel.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			
		}
		
		final long end = System.nanoTime();
		System.out.println("使用 Channe 进行文件赋值用时: " + (end - begin) + "ns.");
	}

}